﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ThreeByte.ActiveDeck.Config;
using System.Xml.Linq;
using ThreeByte.Media;
using log4net;
using System.IO;
using ThreeByte.ActiveDeck.Controls;
using ThreeByte.ActiveDeck.AddIn.Content.Controls;
using ThreeByte.ActiveDeck.AddIn.Config;
using ThreeByte.Controls;
using System.Text.RegularExpressions;

namespace ThreeByte.ActiveDeck.Content
{
    /// <summary>
    /// Interaction logic for UserSlidePreview.xaml
    /// </summary>
    public partial class DesignerSlidePreview : UserControl, IPreviewControl
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(DesignerSlidePreview));

        private DesignerSlideConfig _config;

        public PageConfig Config { get; set; }

        public DesignerSlidePreview(DesignerSlideConfig config) { 
            InitializeComponent();
            _config = config;
            DataContext = config;
            Config = config;

            //Refresh the collection of displayed objects
            //foreach(DesignerControl d in config.Elements) {
            //    ThreeByte.Controls.DesignerCanvas parent = VisualTreeHelper.GetParent(d) as ThreeByte.Controls.DesignerCanvas;
            //    if(parent != null) {
            //        parent.Children.Remove(d);
            //    }
            //    DesignSurface.Children.Add(d);
            //}
        }

        public PresentationPageConfiguration GetPageConfiguration() {
            XNamespace ns = Service.ServiceConfiguration.NAMESPACE;

            PresentationPageConfiguration newPage = new PresentationPageConfiguration();

            XElement pageNode = _config.GetPresentationXml("DesignerSlide"); 

            foreach(DesignerControl d in _config.Elements) {
                pageNode.Add(d.GetPresentationXml());
                foreach(VideoResource v in d.GetMediaResources()) {
                    newPage.MediaResources[v.ID] = v;
                }
                foreach(GraphicResource g in d.GetGraphicResources()) {
                    newPage.Resources[g.ID] = g;
                }
            }

            int i = 1;
            foreach(LayerConfig layer in _config.Layers) {
                layer.Refresh(false); //Update from the Presentation slides if necessary
                //Add the Overlay elements
                XElement layerNode = new XElement(ns + "Layer");
                layerNode.Add(new XAttribute("ID", i++));
                layerNode.Add(new XAttribute("Name", layer.Name));
                layerNode.Add(new XAttribute("Enabled", layer.Show));
                layerNode.Add(new XAttribute("AutoHide", !(layer.Pinned)));
                if(layer.Condition != null) {
                    layerNode.Add(new XAttribute("Condition", layer.Condition));
                }
                
                PixelSpace boundingBox = layer.GetBoundingBox(Config.LayoutOrientation);
                PixelTranslator offset = new PixelTranslator() { XOffset = -1 * boundingBox.X, YOffset = -1 * boundingBox.Y };

                layerNode.Add(new XAttribute("Top", boundingBox.Y));
                layerNode.Add(new XAttribute("Left", boundingBox.X));
                layerNode.Add(new XAttribute("Height", boundingBox.H));
                layerNode.Add(new XAttribute("Width", boundingBox.W));

                foreach(DesignerControl d in layer.Elements) {
                    layerNode.Add(d.GetPresentationXml(offset));
                    foreach(VideoResource v in d.GetMediaResources()) {
                        newPage.MediaResources[v.ID] = v;
                    }
                    foreach(GraphicResource g in d.GetGraphicResources()) {
                        newPage.Resources[g.ID] = g;
                    }
                }
                pageNode.Add(layerNode);
            }

            newPage.ConfigXml = pageNode;
            return newPage;
        }

        private void LayoutRoot_DragEnter(object sender, DragEventArgs e) {
            log.Debug("Drag Enter");
            e.Effects = DragDropEffects.Link;
        }

        private void LayoutRoot_DragLeave(object sender, DragEventArgs e) {

        }

        private void LayoutRoot_DragOver(object sender, DragEventArgs e) {
            //log.Debug("Drag Over");
            e.Effects = DragDropEffects.Link;
            
        }

        //private static PixelScaler DefaultPixelScaler = new PixelScaler() { XScale = (100.0 / 72.0), YScale = (100.0 / 72.0) };
        private static PixelTranslator StatusBarTranslator = new PixelTranslator() { YOffset = -20 };

        private void LayoutRoot_Drop(object sender, DragEventArgs e) {
            log.Debug("Drop");
            
            try {
                string[] formats = e.Data.GetFormats();
                int i = 0;
                foreach(string s in formats) {
                    log.DebugFormat("Format [{0}]: {1}", i++, s);
                }

                //Get Mouse position of drop and insert there
                Point dropPoint = e.GetPosition(DesignSurface);

                //If FileDrop is exposed, then look at the extension
                if(formats.Any(p => (p == DataFormats.FileDrop))) {
                    string path = ((string[])(e.Data.GetData(DataFormats.FileDrop)))[0];
                    string extension = System.IO.Path.GetExtension(path).ToLower();

                    if(extension == @".png"
                        || extension == @".jpg"
                        || extension == @".jpeg") { // Try to parse as an image
                        //Parse as an image

                        DesignerButton newButton = DesignerButton.CreateFromImageFile(path, dropPoint);
                        _config.Elements.Add(newButton);

                    } else if(extension == @".mov") {  // Try to parse as a video
                        //Parse as a video
                        if(ContainsVideo()) {
                            MessageBox.Show("You can only have one video per activity page.", "Video Limit");
                        } else {
                            string pathRoot = Config.ParentSlideConfig.Parent.GetPresentationPath();
                            DesignerVideo dControl = DesignerVideo.CreateFromMediaFile(path, pathRoot, dropPoint);
                            _config.Elements.Add(dControl);
                        }

                    } else {
                        log.InfoFormat("Unrecognized file format: {0}", extension);
                    }

                } else if(formats.Any(p => (p == @"PowerPoint 14.0 Slides Package"))) {

                    //Return Active Slide Range
                    Microsoft.Office.Interop.PowerPoint.SlideRange slideRange = Globals.ThisAddIn.Application.ActiveWindow.Selection.SlideRange;
                    log.DebugFormat("Slide Count: {0} ID:{1} Index:{2} ", slideRange.Count, slideRange.SlideID, slideRange.SlideIndex);
                    
                    //Make sure it is only one slide
                    if(slideRange.Count != 1) {
                        log.Info("Cannot use more than one slide");
                        return;
                    }

                    PixelScaler currentPixelScaler = new PixelScaler();
                    currentPixelScaler.XScale = ((double)(this.Width) / slideRange.Master.Width);
                    currentPixelScaler.YScale = currentPixelScaler.XScale;

                    List<Microsoft.Office.Interop.PowerPoint.Shape> sourceShapes = new List<Microsoft.Office.Interop.PowerPoint.Shape>();
                    List<DesignerControl> controlsToAdd = SlideUtil.GetLayerElements(slideRange[1], ref sourceShapes, (int)Math.Round(this.ActualHeight), (int)Math.Round(this.ActualWidth));
                    

                    //TODO: Not sure if these are utilized properly
                    HashSet<Microsoft.Office.Interop.PowerPoint.Shape> shapesToShow = SlideUtil.GetInteractiveShapes(slideRange[1]);
                    foreach(Microsoft.Office.Interop.PowerPoint.Shape s in shapesToShow) {
                        s.Visible = Microsoft.Office.Core.MsoTriState.msoFalse;
                    }
                    foreach(Microsoft.Office.Interop.PowerPoint.Shape s in sourceShapes) {
                        s.Visible = Microsoft.Office.Core.MsoTriState.msoFalse;
                        shapesToShow.Add(s);
                    }
                    
                    //Remove all objects currently on the page
                    _config.Elements.Clear();
                    //DesignSurface.Children.Clear();

                    GraphicResource newResource = new GraphicResource(SlideUtil.Snapshot(slideRange), string.Format("SlideSnapshot_{0}", slideRange.SlideID), ImageType.JPEG);
                    //Create page sized PixelSpace
                    PixelSpace fullPage = new PixelSpace() { W = (int)Math.Round(this.ActualWidth), H = (int)Math.Round(this.ActualHeight), X = 0, Y = 0 };
                    DesignerImage dControl = new DesignerImage(newResource, fullPage) { Fill = true, VerticalAlignment = System.Windows.VerticalAlignment.Bottom };
                    _config.Elements.Add(dControl);

                    foreach(DesignerControl c in controlsToAdd) {
                        //if(!(c is DesignerImage)) {
                            _config.Elements.Add(c);
                        //}
                    }

                    //Make shapes visible again.
                    foreach(Microsoft.Office.Interop.PowerPoint.Shape s in shapesToShow) {
                        s.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
                    }

                } else if(formats.Any(p => (p == DataFormats.Text))){
                    string droppedUrl = e.Data.GetData(DataFormats.Text, true).ToString();

                    Regex reg = new Regex(@"(http(s)?://)?([\w-]+\.)+[\w-]+(/[\w- ;,./?%&=]*)?");
                   
                    if(reg.IsMatch(droppedUrl)) {
                        PixelSpace webViewSpace = new PixelSpace() { X = (int)Math.Round(dropPoint.X), Y = (int)Math.Round(dropPoint.Y), W = 200, H = 200 };
                        DesignerWebView webView = new DesignerWebView(droppedUrl, webViewSpace);

                        _config.Elements.Add(webView);
                    }                    

                }
                //else if(formats.Any(p => (p == @"System.Windows.Controls.Button"))) {
                //    //Drop a new button on to the designer canvas
                //    ActionButton newActionButton = new ActionButton();

                //    DesignerControl dControl = new DesignerControl(newActionButton, new PixelSpace() { W = 150, H = 40, X = 300, Y = 300 });
                //    //DesignSurface.Children.Add(dControl);
                //    _config.Elements.Add(dControl);
                //}

            } catch(Exception ex) {
                log.Fatal("Collossal Fail", ex);
            }
        }

        private bool ContainsVideo() {
            foreach(DesignerControl c in _config.Elements) {
                if(c is DesignerVideo) {
                    return true;
                }
            }
            return false;
        }

        private void DesignSurface_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            log.DebugFormat("Selection Changed: {0}", e);

            if(e.AddedItems.Count == 1) {
                object selectedObject = e.AddedItems[0];
                Globals.ThisAddIn.GetPropertiesControl().Show(selectedObject);

                //if(selectedObject is DesignerVideo) {
                //    //Show the properties pane for this object
                //    Globals.ThisAddIn.GetPropertiesControl().Show(selectedObject as DesignerVideo);
                //}
            }
        }

        private void DesignSurface_KeyDown(object sender, KeyEventArgs e) {

        }

        private void DesignSurface_ItemDeleted(object sender, ItemDeletedEventArgs e) {
            DesignerControl deletedItem = e.Item as DesignerControl;
            if(deletedItem != null) {
                _config.Elements.Remove(deletedItem);
            }
        }
    }
}
